/*
 * F-List Pidgin - a libpurple protocol plugin for F-Chat
 *
 * Copyright 2011 F-List Pidgin developers.
 *
 * This file is part of F-List Pidgin.
 *
 * F-List Pidgin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * F-List Pidgin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with F-List Pidgin.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "f-list_autobuddy.h"

static GSList *flist_get_filter_characters(PurpleConnection *pc, gboolean has_extra, GSList *extra) {
    PurpleAccount *pa = purple_connection_get_account(pc);
    FListAccount *fla = pc->proto_data;
    int list_count = 0;
    GSList *list1 = NULL, *list2 = NULL;
    GSList *ret = NULL, *tmp = NULL;

    if(fla->filter_channel) {
        list2 = list1; list1 = NULL; list_count++;
        PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, fla->filter_channel, pa);
        if(convo) {
            purple_debug_info("flist", "We filtered on channel %s.\n", fla->filter_channel);
            GList *chat_users = purple_conv_chat_get_users(PURPLE_CONV_CHAT(convo));
            GList *cur = chat_users;
            while(cur) {
                PurpleConvChatBuddy *b = cur->data;
                FListCharacter *character = flist_get_character(fla, b->name);
                if(character) list1 = g_slist_prepend(list1, character);
                cur = g_list_next(cur);
            }
        } else {
            purple_debug_info("flist", "We tried to filter on channel %s, but no channel was found.\n", fla->filter_channel);
        }
    }
    if(has_extra) {
        list2 = list1; list1 = NULL; list_count++;
        GSList *cur = extra;
        while(cur) {
            FListCharacter *character = flist_get_character(fla, cur->data);
            if(character) list1 = g_slist_prepend(list1, character);
            cur = g_slist_next(cur);
        }
    }
    if(list_count == 0) {
        list1 = flist_get_all_characters(fla); list_count++;
    }
    if(list_count == 1) {
        ret = list1;
    }
    if(list_count == 2) {
        ret = flist_g_slist_intersect_and_free(list1, list2);
    }
    
    GSList *cur = ret;
    while(cur) {
        FListCharacter *flc = cur->data;
        if(!fla->filter_looking || flc->status == FLIST_STATUS_LOOKING) {
            tmp = g_slist_prepend(tmp, flc->name); /* duplicate this maybe? */
        }
        cur = g_slist_next(cur);
    }

    g_slist_free(ret);

    return tmp;
}

void flist_apply_filter_real(PurpleConnection *pc, GSList *candidates) {
    PurpleAccount *pa = purple_connection_get_account(pc);
    FListAccount *fla = pc->proto_data;
    PurpleGroup *filter_group = NULL;
    GSList *buddies, *cur;
    GSList *removed = NULL;

    filter_group = flist_get_filter_group(fla);
    
    buddies = purple_find_buddies(pa, NULL);
    cur = buddies;
    while(cur) {
        PurpleBuddy *b = cur->data; cur = g_slist_next(cur);
        const gchar *name = purple_buddy_get_name(b);
        if(purple_buddy_get_group(b) == filter_group) {
            if(!g_slist_find_custom(candidates, name, (GCompareFunc) flist_strcmp)) { //TODO: this is extremely inefficient, fix it!
                removed = g_slist_prepend(removed, b);
            }
        }
    }
    g_slist_free(buddies);

    cur = removed;
    while(cur) {
        PurpleBuddy *b = cur->data; cur = g_slist_next(cur);
        purple_blist_remove_buddy(b);
    }
    g_slist_free(removed);

    cur = candidates;
    while(cur) {
        const gchar *name = cur->data; cur = g_slist_next(cur);
        purple_debug_info("flist", "adding %s\n", name);
        PurpleBuddy *b = purple_find_buddy(pa, name);
        if(!b) { /* we're adding a new buddy */
            b = purple_buddy_new(pa, name, NULL);
            purple_blist_add_buddy(b, NULL, filter_group, NULL);
            purple_account_add_buddy(pa, b);
        } /* do nothing if this is already a buddy */
    }
}

void flist_apply_filter(PurpleConnection *pc, gboolean has_extra, GSList *extra) {
    GSList *candidates = flist_get_filter_characters(pc, has_extra, extra);
    flist_apply_filter_real(pc, candidates);
    g_slist_free(candidates);
}

void flist_clear_filter(PurpleConnection *pc) {
    flist_apply_filter_real(pc, NULL);
}
